﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CCPnuts.Pack;
using CCPnuts.IFileSplit.Interfaces;
using System.IO;
using CCPnuts.Base;

namespace CCPnuts.IFileSplit
{
    public class Spliter : PackerBase
    {
        #region Packed Target

        internal Spliter(IPacked packed) : base(packed) { }

        internal new I_Spliter Packed { get { return (I_Spliter)base.Packed; } }

        #endregion

        #region Construstors

        public Spliter() : this(InterfaceManager.Spliter._Cons()) { }

        public Spliter(string sourceFile) : this(InterfaceManager.Spliter._Cons(sourceFile)) { }

        #endregion

        #region Proxy Members

        #region Essential Members

        /// <summary>
        /// Gets or sets the size of each split file.
        /// </summary>
        public long SplitSize
        {
            get
            {
                try
                {
                    return Packed.SplitSize;
                }
                catch (Exception ex)
                {
                    throw ex.Pack("Exception @ Spliter : SplitSize : Get");
                }
            }
            set
            {
                try
                {
                    Packed.SplitSize = value;
                }
                catch (Exception ex)
                {
                    throw ex.Pack("Exception @ Spliter : SplitSize : Set");
                }
            }
        }

        /// <summary>
        /// Gets or sets the source file.
        /// </summary>
        public string SourceFile
        {
            get
            {
                try
                {
                    return Packed.SourceFile;
                }
                catch (Exception ex)
                {
                    throw ex.Pack("Exception @ Spliter : SourceFile : Get");
                }
            }
            set
            {
                try
                {
                    Packed.SourceFile = value;
                }
                catch (Exception ex)
                {
                    throw ex.Pack("Exception @ Spliter : SourceFile : Set");
                }
            }
        }

        /// <summary>
        /// Gets or sets the tareget directory.
        /// </summary>
        public string TargetDirectory
        {
            get
            {
                try
                {
                    return Packed.TargetDirectory;
                }
                catch (Exception ex)
                {
                    throw ex.Pack("Exception @ Spliter : TargetDirectory : Get");
                }
            }
            set
            {
                try
                {
                    Packed.TargetDirectory = value;
                }
                catch (Exception ex)
                {
                    throw ex.Pack("Exception @ Spliter : TargetDirectory : Set");
                }
            }
        }

        /// <summary>
        /// Split the file. This is a synchronous method.
        /// </summary>
        public void Split()
        {
            try
            {
                Packed.Split();
            }
            catch (Exception ex)
            {
                throw ex.Pack("Exception @ Spliter : Split");
            }
        }

        #endregion

        #region Optional Members

        /// <summary>
        /// Gets the size of the source file. 
        /// </summary>
        [Optional]
        public long FileSize
        {
            get
            {
                try
                {
                    return Packed.FileSize;
                }
                catch (NotImplementedException)
                {
                    var file = new FileInfo(SourceFile);
                    if (!file.Exists)
                    {
                        throw new FileNotFoundException(SourceFile);
                    }
                    return file.Length;
                }
                catch (Exception ex)
                {
                    throw ex.Pack("Exception @ Spliter : FileSize : Get");
                }
            }
        }

        /// <summary>
        /// Gets or sets the number of the part files.
        /// </summary>
        [Optional]
        public int FileCount
        {
            get
            {
                try
                {
                    return Packed.FileCount;
                }
                catch (NotImplementedException)
                {
                    return (int)(FileSize / SplitSize) + 1;
                }
                catch (Exception ex)
                {
                    throw ex.Pack("Exception @ Spliter : FileCount : Get");
                }
            }
        }

        /// <summary>
        /// Begin a split. This is a asynchronous method.
        /// </summary>
        [Optional]
        IAsyncResult BeginSplit(AsyncCallback callback)
        {
            try
            {
                return Packed.BeginSplit(callback);
            }
            catch (NotImplementedException)
            {
                AsyncReturnDelegate dele = new AsyncReturnDelegate(this.Split);
                return dele.BeginInvoke(callback, dele);
            }
            catch (Exception ex)
            {
                throw ex.Pack("Exception @ Spliter : Begin Split(AsyncCallback)");
            }
        }

        /// <summary>
        /// End a split. This is a asynchronous method.
        /// </summary>
        /// <param name="result"></param>
        [Optional]
        void EndSplit(IAsyncResult result)
        {
            try
            {
                Packed.EndSplit(result);
            }
            catch (NotImplementedException)
            {
                AsyncReturnDelegate dele = (AsyncReturnDelegate)result.AsyncState;
                dele.EndInvoke(result);
            }
            catch (Exception ex)
            {
                throw ex.Pack("Exception @ Spliter : EndSplit(IAsyncResult)");
            }
        }

        #endregion

        #endregion
    }

    public partial class PackedInfos
    {
        public static PackedInfo Spliter { get { return new PackedInfo(p => new Spliter(p)); } }
    }
}
